package stats;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;

import stats.CharStat.*;

public class Profile {
	private String playerName;
	private String[] petArray = {};
	static HashMap<String, ArrayList<ArrayList<Integer>>> jLvlTable = null;
	private Hashtable<String, Equips> equips = new Hashtable<String, Equips>();
	private String beltPet;
	private int level, jLvl, str, vit, agi, intel, wis, dex, luck, total = 0;
	private int atkSpd;
	private Deva devaJob = null;
	private Asura asuraJob = null;
	private Gaia gaiaJob = null;	
	public static final int MAXLEVEL = 170;
	
	public Profile() throws IOException{
		this.playerName = "Default";
		this.jLvl = 10;
		this.level = 1;
		devaJob = Deva.SoulBreeder;
		if (jLvlTable == null){
			jLvlTable = FileReaderWriter.jLvlTableRead();
		}
		//addDefaultEquip();
		initializeStats();
	}
	
	public Profile(String name) throws IOException{
		this.playerName = name;
		this.jLvl = 1;
		this.level = 1;
		devaJob = Deva.Guide;
		if (jLvlTable == null){
			jLvlTable = FileReaderWriter.jLvlTableRead();
		}
		//addDefaultEquip();
		initializeStats();
	}
	
	public void setJob(Asura job){
		asuraJob = job;
		devaJob = null;
		gaiaJob = null;
		initializeStats();
		}
	
	public void setJob(Deva job){
		asuraJob = null;
		devaJob = job;
		gaiaJob = null;
		initializeStats();
		}
	
	public void setJob(Gaia job){
		asuraJob = null;
		devaJob = null;
		gaiaJob = job;
		initializeStats();
		}
	
	private void addDefaultEquip() throws IOException{
		addEquip(new Armor(EnumArmor.Helmet, "Helm", 1, 0, 10, 10, 20, 20));
		//addEquip(new Armor(10, 10, 20, EnumArmor.Gloves));
		//addEquip(new Armor(10, 10, 20, EnumArmor.Boots));
		//addEquip(new Armor(10, 10, 20, EnumArmor.Cloak));
		//addEquip(new Weapon1h(100, 100, 0, 200, EnumWeapons.Blunt1h));
		//addEquip(new Armor(10, 10, 20, EnumArmor.Shield));
		//addEquip(new Armor(100, 100, 100, EnumArmor.Warrior));
		
		equips.get("Helmet").addStones("vit", 12, 0);
		equips.get("Helmet").addStones("str", 12, 1);
		
	}
	
	public String getLevel(){
		return String.valueOf(level);
	}
	
	public void setLevel(int lvl){
		level = lvl;
		initializeStats();
		}
	
	public String getJLevel(){
		return String.valueOf(jLvl);
	}
	
	public void setJLevel(int jLvl){
		this.jLvl = jLvl;
		initializeStats();
		}
	
	public String getName(){
		return playerName;
	}
	
	public void setName(String name){
		playerName = name;
	}
	
	public String getStr(){
		return String.valueOf(str);
	}
	
	public String getVit(){
		return String.valueOf(vit);
	}
	
	public String getAgi(){
		return String.valueOf(agi);
	}
	
	public String getIntel(){
		return String.valueOf(intel);
	}
	
	public String getWis(){
		return String.valueOf(wis);
	}
	
	public String getDex(){
		return String.valueOf(dex);
	}
	
	public String getLuck(){
		return String.valueOf(luck);
	}
	
	public String getTotal(){
		return String.valueOf(total);
	}
	
	public String getAtkSpd(){
		//AtkSpd = 100 + Equip + Skill + Buff
		int equipBonus = 0;		
		for (String s: equips.keySet()){
			equipBonus += equips.get(s).atkSpd;
		}
		atkSpd = 100 + equipBonus;
		return String.valueOf(atkSpd);
	}
	
	public String getJob(){
		if (devaJob != null){
			return devaJob.toString();
		}else if (asuraJob != null){
			return asuraJob.toString();
		}else if (gaiaJob != null){
			return gaiaJob.toString();
		}
		return Deva.Guide.toString();
	}
	
	public static ArrayList<ArrayList<Integer>> getTable(String job){
		return jLvlTable.get(job);
	}
	
	
	public void addEquipBaseStats(){
		for(String s: equips.keySet()){
			Equips equip = equips.get(s);
			str += equip.str;
			vit += equip.vit;
			agi += equip.agi;
			intel += equip.intel;
			wis += equip.wis;
			dex += equip.dex;
			luck += equip.luck;
		}
		total = str + vit + agi + intel + wis + dex + luck;
	}
	
	
	public int getMaxHP(){
		// MaxHP = 30*Vit + 20*Lv + Equip + Skill + Buff
		
		int equipBonus = 0;		
		for (String s: equips.keySet()){
			equipBonus += equips.get(s).maxMP;
		}
		
		int maxHP = (int) Math.round((float)(30*vit + 20*level + equipBonus));
		return maxHP;
	}
	
	public int getMaxMP(){
		//MaxMP = 30*Int + 20*Lv + Equip + Skill + Buff
		
		int equipBonus = 0;		
		for (String s: equips.keySet()){
			equipBonus += equips.get(s).maxMP;
		}
		
		return (int) Math.round((float)(30*intel + 20*level + equipBonus));
	}
	
	public int getPAtk(){
		//P.Atk Melee = 2*Str + 1*Lv + Equip + Skill + Buff
		//P.Atk Ranged = (3/8)*Str + (13/8)*Dex + 1*Lv + Equip + Skill + Buff 
		String weapon = "";
		if (equips.containsKey("Weapon")){
			weapon = equips.get("Weapon").type();
		}
		int equipBonus = 0;
		for (String s: equips.keySet()){
			equipBonus += equips.get(s).pAtk;
		}
		if (weapon.contains("Bow")){
			return (int) Math.round((float) (0.375*str + 1.625*dex + 1.0*level + equipBonus));
		} else {
			return (int) Math.round((float) (2.0*str + 1*level + equipBonus));
		}
	}
	
	public int getMAtk(){
		//M.Atk = 2*Int + 1*Lv + Equip + Skill + Buff 
		int equipBonus = 0;		
		for (String s: equips.keySet()){
			equipBonus += equips.get(s).mAtk;
		}
		return (int) Math.round((float) (2.0*intel + 1*level + equipBonus));
	}
	
	public int getAcc(){
		//Acc = (1/2)*Dex + 1*Lv + Equip + Skill + Buff 

		return (int) Math.round((float) (0.5*dex + 1*level)); 
	}
	
	public int getMAcc(){
		//M.Acc = (4/10)*Wis + (1/10)*Dex + 1*Lv + Equip + Skill + Buff
		
		return (int) Math.round((float)((float)(0.4*wis) + (float)(0.1*dex) + 1*level)); 
	}
	
	public int getPDef(){
		//P.Def = 2*Vit + 1*Lv + Equip + Skill + Buff 
		
		int equipBonus = 0;		
		for (String s: equips.keySet()){
			equipBonus += equips.get(s).pDef;
		}
		
		return (2 * vit + level + equipBonus);
	}
	
	public int getMDef(){
		//M.Def = 2*Wis + 1*Lv + Equip + Skill + Buff
		
		int equipBonus = 0;		
		for (String s: equips.keySet()){
			equipBonus += equips.get(s).mDef;
		}
		
		return (2*wis + level + equipBonus);
	}
	
	public int getEvasion(){
		//Evasion = (1/2)*Agi + 1*Lv + Equip + Skill + Buff
		return (int) Math.round((float)(.5*agi + level));
	}
	
	public int getMRes(){
		//M.Res = (1/2)*Wis + 1*Lv + Equip + Skill + Buff
		
		int equipBonus = 0;		
		for (String s: equips.keySet()){
			equipBonus += equips.get(s).magRes;
		}
		
		return (int) Math.round((float)(.5*wis + level + equipBonus));
	}
	
	public int getMovSpd(){
		//MovSpd = 120 + Equip + Skill + Buff
		
		int equipBonus = 0;		
		for (String s: equips.keySet()){
			equipBonus += equips.get(s).movSpd;
		}
		
		return 120 + equipBonus;
	}
	
	public float getHPRegen(){
    //HP.Regen = 5 + Equip + Skill + Buff
		return 0.05f;
	}
	
	public float getMPRegen(){
    //MP.Regen = 5 + Equip + Skill + Buff
		return 0.05f;
	}
	
	public float getBlockPer(){
    //BlockPer = Equip + Skill + Buff
		
		float equipBonus = 0;		
		for (String s: equips.keySet()){
			equipBonus += equips.get(s).blockRate;
		}
		
		return 0 + equipBonus;
	}
	public int getCriRatio(){
    //CriRatio = (1/5)*Luck + 3 + Equip + Skill + Buff
		
		int equipBonus = 0;		
		for (String s: equips.keySet()){
			equipBonus += equips.get(s).criChance;
		}
		
		return (int) Math.round((float)(0.2*luck + 3.0 + equipBonus));
	}
    
	public int getCastSpd(){
		//CastSpd = 100 + Equip + Skill + Buff
		return 100;
	}

    public int getHPRecov(){
    	//HP.Recov = 2*Lv + 48 + Equip + Skill + Buff
    	
		int equipBonus = 0;		
		for (String s: equips.keySet()){
			equipBonus += equips.get(s).hpRec;
		}
    	
    	return (2 * level + 48 + equipBonus);
    }
    
    public int getMPRecov(){
    	//MP.Recov = 2*Lv + 48 + Equip + Skill + Buff
    	
		int equipBonus = 0;		
		for (String s: equips.keySet()){
			equipBonus += equips.get(s).mpRec;
		}
    	
    	return (2*level + 48 + equipBonus);
    }
    
    public int getBlockDef(){
    	//BlockDef = 0 + Equip + Skill + Buff
    	return 0;
    }
    
    public int getCriPow(){
    	//CriPow = 80 + Equip + Skill + Buff
    	
		int equipBonus = 0;		
		for (String s: equips.keySet()){
			equipBonus += equips.get(s).criPow;
		}
    	
    	return 80 + equipBonus;
    }
    
    public int getRecast(){
    	//Recast = 100 + Equip + Skill + Buff
    	return 100;
    }

    public int getMaxWT(){
    	//MaxWT = 10*Str +10*Lv + Equip + Skill + Buff
    	
		int equipBonus = 0;		
		for (String s: equips.keySet()){
			equipBonus += equips.get(s).maxWTInc;
		}
    	
    	return (10*str + 10*level + equipBonus);
    }
    
    public int getHPRecPerMin(){
    	//HP recovered each minute standing = MaxHP * HP.Regen + HP.Recov 
    	
    	int maxHP = getMaxHP();
    	float hpRegen = getHPRegen();
    	int hpRec = getHPRecov();
    	
    	return (int) Math.round((float)((float)maxHP * hpRegen + (float)hpRec));
    }
    
    public int getMPRecPerMin(){
    	//MP recovered each minute standing = MaxMP * MP.Regen + MP.Recov 
    	int maxMP = getMaxMP();
    	float mpRegen = getMPRegen();
    	int mpRec = getMPRecov();
    	
    	return (int) Math.round((float)((float)maxMP * mpRegen + (float)mpRec));
    }

    public void addEquip(Equips equip){
    	if (equip == null){
    		return;
    	}
    	String name = equip.equipType.getClass().getSimpleName();
    	if (name.equals("EnumArmor")){
    		if (equip.type().equals("Shield")){
    			if(equips.containsKey("Weapon")){
    				if(equips.get("Weapon").type().contains("2h")){
    					equips.remove("Weapon");
    					equips.put("Shield", equip);
    					initializeStats();
    					return;
    				}
    				equips.put("Shield", equip);
    				initializeStats();
    				return;
    			}
    			equips.put("Shield", equip);
    			initializeStats();
    			return;
    		}
    		equips.put(equip.worn, equip);
    		initializeStats();
    		return;
    	} else if(name.equals("EnumWeapons")){
    		if (equip.type().contains("1h") || equip.type().equals("Dagger")){
    			if (equips.containsKey("Weapon")){
    				if(equips.get("Weapon").type().contains("1h") || equips.get("Weapon").type().equals("Dagger")){
    					equips.put("Shield", equip);
    					initializeStats();
    					return;
    				}
    			}
    			equips.put("Weapon", equip);
    			initializeStats();
				return;
    		}
    		equips.remove("Shield");
    		equips.put("Weapon", equip);
    		initializeStats();
			return;
    	} else if(name.equals("EnumAccessories")){
    		if (equip.worn.equals("Ring")){
    			if (equips.containsKey("Ring1")){
    				equips.put("Ring2", equip);
    				initializeStats();
    				return;
    			}
    			equips.put("Ring1", equip);
    			initializeStats();
    			return;
    		}
    		equips.put(equip.worn, equip);
    	}
    }
    
	private void setJLvlStats(){
		
		int newJLvl;
		CharStat.jobNode job = CharStat.getJobTree().get(getJob());
		ArrayList<ArrayList<Integer>> jTable = null;
		jTable = getTable(job.getName());
		
		newJLvl = Math.min(jLvl, jTable.size());
		for (int i=0; i<newJLvl; i++){
			str += jTable.get(i).get(0);
			vit += jTable.get(i).get(1);
			agi += jTable.get(i).get(2);
			intel += jTable.get(i).get(3);
			wis += jTable.get(i).get(4);
			dex += jTable.get(i).get(5);
			luck += jTable.get(i).get(6);
		}
		
		CharStat.jobNode parent = job.getParent();
		while (parent != null){
			jTable = getTable(parent.getName());
			for (int i=0; i<jTable.size(); i++){
				str += jTable.get(i).get(0);
				vit += jTable.get(i).get(1);
				agi += jTable.get(i).get(2);
				intel += jTable.get(i).get(3);
				wis += jTable.get(i).get(4);
				dex += jTable.get(i).get(5);
				luck += jTable.get(i).get(6);
			}
			parent = parent.getParent();
		}
		total = str + vit + agi + intel + wis + dex + luck;
		/*System.out.println(total);
		System.out.println(getMaxHP());
		System.out.println(getMaxMP());
		System.out.println(getPAtk());
		System.out.println(getMAtk());
		System.out.println(getAcc());
		System.out.println(getMAcc());
		System.out.println(getPDef());
		System.out.println(getMDef());
		System.out.println(getEvasion());
		System.out.println(getMRes());
		System.out.println(getMovSpd());
		System.out.println(getHPRegen());
		System.out.println(getMPRegen());
		System.out.println(getBlockPer());
		System.out.println(getCriRatio());
		System.out.println(getCastSpd());
		System.out.println(getHPRecov());
		System.out.println(getMPRecov());
		System.out.println(getBlockDef());
		System.out.println(getCriPow());
		System.out.println(getRecast());
		System.out.println(getMaxWT());
		System.out.println(getHPRecPerMin());
		System.out.println(getMPRecPerMin());
		*/
	}
	
	private void initializeStats(){
		str = 0; vit = 0; agi = 0; intel = 0; wis= 0; dex= 0; luck= 0; total = 0;
		setJLvlStats();
		addEquipBaseStats();
	}
	
	public String export(){
		StringBuilder result = new StringBuilder();
		String NEW_L = System.getProperty("line.separator");
		result.append("PlayerName\t" + this.playerName + NEW_L);
		result.append("Job\t" + getJob() + NEW_L);
		result.append("Level\t" + this.level + NEW_L);
		result.append("JobLevel\t" + this.jLvl + NEW_L);
		result.append("Pets\t");
		if (petArray.length > 0){
			for (String s : this.petArray){
				result.append(s+","+NEW_L);
				}
		} else {
			result.append("none"+NEW_L);
		}
		result.append("BeltPet\t");
		if (beltPet != null){
			result.append(beltPet);
		} else {
			result.append("none"+NEW_L);
		}
		for (String s: equips.keySet()){
			result.append(equips.get(s).givenStats()+NEW_L);
		}
		String temp = String.format("%s,%s,%s,%s,%s,%s,%s",str,vit,agi,intel,wis,dex,luck);
		result.append(temp+NEW_L);
		return result.toString();
	}
	
	public static void main(String[] args){
		Profile r = null;
		try {
			r = new Profile();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			for(Equips e:FileReaderWriter.getAccessoriesList()){
				r.addEquip(e);
			}
			for(Equips e:FileReaderWriter.getArmorList()){
				r.addEquip(e);
			}
			for(Equips e:FileReaderWriter.getWeaponsList()){
				r.addEquip(e);
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(r.export());
	}
}
